
#include "stdint.h"
#include "spi_flash.h"

/* -------------------------------- begin  -------------------------------- */
/**
  * @Name    SPI_RW_Byte
  * @brief
  * @param   byte: [输入/出]
  * @retval
  * @author  {}
  * @Data    2023-03-02
 **/
/* -------------------------------- end -------------------------------- */

static uint16_t SPI_RW_Byte(uint16_t byte)
{
    /*!< Loop while DAT register in not emplty */
    while (SPI_I2S_GetStatus(SPI1, SPI_I2S_TE_FLAG) == RESET)
        ;
    /*!< Send byte through the SPI1 peripheral */
    SPI_I2S_TransmitData(SPI1, byte);
    /*!< Wait to receive a byte */
    while (SPI_I2S_GetStatus(SPI1, SPI_I2S_RNE_FLAG) == RESET)
        ;
    /*!< Return the byte read from the SPI bus */
    return SPI_I2S_ReceiveData(SPI1);
}

/* -------------------------------- begin  -------------------------------- */
/**
  * @Name    SPIFLASH_CSN_SET
  * @brief
  * @param   devNum: [输入/出]
**			 selected: [输入/出]
  * @retval
  * @author  {}
  * @Data    2023-03-02
 **/
/* -------------------------------- end -------------------------------- */

static void SPIFLASH_CSN_SET(uint8_t devNum,uint8_t selected)
{
    switch(devNum)
    {
    case 0:
        if(selected == 0)
            GPIO_ResetBits(GPIOA, GPIO_PIN_4);
        else
            GPIO_SetBits(GPIOA, GPIO_PIN_4);
        break;
    }
}

/* -------------------------------- begin  -------------------------------- */
/**
  * @Name    SPIFLASH_readWriteByte
  * @brief
  * @param   devNum: [输入/出]
**			 txData: [输入/出]
  * @retval
  * @author  {}
  * @Data    2023-03-02
 **/
/* -------------------------------- end -------------------------------- */

static uint16_t SPIFLASH_readWriteByte(uint8_t devNum, uint8_t txData )
{
    uint16_t rxData;

    switch(devNum) {
    case 0:
        rxData = SPI_RW_Byte(txData);
        break;
    case 1:
        break;
    }
    return(rxData);
}

/* -------------------------------- begin  -------------------------------- */
/**
  * @Name    SPIFLASH_write_Page
  * @brief
  * @param   devNum: [输入/出]
**			 pBuffer: [输入/出]
**			 WriteAddr: [输入/出]
**			 NumByteToWrite: [输入/出]
  * @retval
  * @author  {}
  * @Data    2023-03-02
 **/
/* -------------------------------- end -------------------------------- */

static uint8_t SPIFLASH_write_Page( uint8_t devNum,unsigned char* pBuffer, unsigned long int WriteAddr, unsigned short int NumByteToWrite )
{
    unsigned short int i;
    SPIFLASH_writeEnable(devNum);
    SPIFLASH_CSN_SET( devNum, 0);
    SPIFLASH_readWriteByte(devNum, SPIFLASH_PageProgram );
    SPIFLASH_readWriteByte(devNum, (unsigned char) ( (WriteAddr) >> 16) );
    SPIFLASH_readWriteByte(devNum, (unsigned char) ( (WriteAddr) >> 8) );
    SPIFLASH_readWriteByte(devNum, (unsigned char) WriteAddr );
    for ( i = 0; i < NumByteToWrite; i++ )
        SPIFLASH_readWriteByte(devNum, pBuffer[i] );
    SPIFLASH_CSN_SET( devNum, 1);
    SPIFLASH_waitBusy(devNum);
    return 0;
}


/* -------------------------------- begin  -------------------------------- */
/**
  * @Name    SPIFLASH_init
  * @brief
  * @param   devNum: [输入/出]
  * @retval
  * @author  {}
  * @Data    2023-03-02
 **/
/* -------------------------------- end -------------------------------- */

uint16_t SPIFLASH_init(  uint8_t devNum )
{
    switch(devNum) {
    case BSP_SPI_DEV_FLASH_0:
        devNum=0;
        break;
    case BSP_SPI_DEV_FLASH_1:
        devNum=1;
        break;
    }

    SPIFLASH_wakeUp(devNum);
    return SPIFLASH_readID(devNum);
}

/* -------------------------------- begin  -------------------------------- */
/**
  * @Name    SPIFLASH_readID
  * @brief
  * @param   devNum: [输入/出]
  * @retval
  * @author  {}
  * @Data    2023-03-02
 **/
/* -------------------------------- end -------------------------------- */

unsigned short int SPIFLASH_readID( uint8_t devNum )
{
    unsigned short int Temp = 0;
    SPIFLASH_CSN_SET( devNum, 0);
    SPIFLASH_readWriteByte(devNum, 0x90 );
    SPIFLASH_readWriteByte(devNum, 0x00 );
    SPIFLASH_readWriteByte(devNum, 0x00 );
    SPIFLASH_readWriteByte(devNum, 0x00 );
    Temp |= SPIFLASH_readWriteByte(devNum, 0xFF ) << 8;
    Temp |= SPIFLASH_readWriteByte(devNum, 0xFF );
    SPIFLASH_CSN_SET( devNum, 1);
    return(Temp);
}

/* -------------------------------- begin  -------------------------------- */
/**
  * @Name    SPIFLASH_readSR
  * @brief
  * @param   devNum: [输入/出]
  * @retval
  * @author  {}
  * @Data    2023-03-02
 **/
/* -------------------------------- end -------------------------------- */

unsigned char SPIFLASH_readSR( uint8_t devNum )
{
    unsigned char byte = 0;
    SPIFLASH_CSN_SET( devNum, 0);
    SPIFLASH_readWriteByte(devNum, SPIFLASH_ReadStatusReg );
    byte = SPIFLASH_readWriteByte(devNum, 0Xff );
    SPIFLASH_CSN_SET( devNum, 1);
    return(byte);
}

/* -------------------------------- begin  -------------------------------- */
/**
  * @Name    SPIFLASH_writeSR
  * @brief
  * @param   devNum: [输入/出]
**			 sr: [输入/出]
  * @retval
  * @author  {}
  * @Data    2023-03-02
 **/
/* -------------------------------- end -------------------------------- */

void SPIFLASH_writeSR( uint8_t devNum,unsigned char sr )
{
    SPIFLASH_CSN_SET( devNum, 0);
    SPIFLASH_readWriteByte(devNum, SPIFLASH_WriteStatusReg );
    SPIFLASH_readWriteByte( devNum,sr );
    SPIFLASH_CSN_SET( devNum, 1);
}

/* -------------------------------- begin  -------------------------------- */
/**
  * @Name    SPIFLASH_writeEnable
  * @brief
  * @param   devNum: [输入/出]
  * @retval
  * @author  {}
  * @Data    2023-03-02
 **/
/* -------------------------------- end -------------------------------- */

void SPIFLASH_writeEnable( uint8_t devNum )
{
    SPIFLASH_CSN_SET( devNum, 0);
    SPIFLASH_readWriteByte(devNum, SPIFLASH_WriteEnable );
    SPIFLASH_CSN_SET( devNum, 1);
}

/* -------------------------------- begin  -------------------------------- */
/**
  * @Name    SPIFLASH_writeDisable
  * @brief
  * @param   devNum: [输入/出]
  * @retval
  * @author  {}
  * @Data    2023-03-02
 **/
/* -------------------------------- end -------------------------------- */

void SPIFLASH_writeDisable( uint8_t devNum )
{
    SPIFLASH_CSN_SET( devNum, 0);
    SPIFLASH_readWriteByte(devNum, SPIFLASH_WriteDisable );
    SPIFLASH_CSN_SET( devNum, 1);
}


/* -------------------------------- begin  -------------------------------- */
/**
  * @Name    SPIFLASH_writeNoCheck
  * @brief
  * @param   devNum: [输入/出]
**			 pBuffer: [输入/出]
**			 WriteAddr: [输入/出]
**			 NumByteToWrite: [输入/出]
  * @retval
  * @author  {}
  * @Data    2023-03-02
 **/
/* -------------------------------- end -------------------------------- */

void SPIFLASH_writeNoCheck(unsigned char devNum, unsigned char* pBuffer, unsigned long int WriteAddr, unsigned short int NumByteToWrite )
{
    unsigned short int pageremain;
    pageremain = 256 - WriteAddr % 256;
    if ( NumByteToWrite <= pageremain )
        pageremain = NumByteToWrite;
    while ( 1 )
    {
        SPIFLASH_write_Page(devNum, pBuffer, WriteAddr, pageremain );
        if ( NumByteToWrite == pageremain )
            break;
        else {
            pBuffer		+= pageremain;
            WriteAddr	+= pageremain;

            NumByteToWrite -= pageremain;
            if ( NumByteToWrite > 256 )
                pageremain = 256;
            else pageremain = NumByteToWrite;
        }
    };
}

/* -------------------------------- begin  -------------------------------- */
/**
  * @Name    SPIFLASH_read
  * @brief
  * @param   devNum: [输入/出]
**			 pBuffer: [输入/出]
**			 ReadAddr: [输入/出]
**			 NumByteToRead: [输入/出]
  * @retval
  * @author  {}
  * @Data    2023-03-02
 **/
/* -------------------------------- end -------------------------------- */

uint8_t SPIFLASH_read(uint8_t devNum, unsigned char* pBuffer, unsigned long int ReadAddr, unsigned short int NumByteToRead )
{
    unsigned short int i;
    SPIFLASH_CSN_SET( devNum,0);
    SPIFLASH_readWriteByte(devNum, SPIFLASH_ReadData );
    SPIFLASH_readWriteByte(devNum, (unsigned char) ( (ReadAddr) >> 16) );
    SPIFLASH_readWriteByte(devNum, (unsigned char) ( (ReadAddr) >> 8) );
    SPIFLASH_readWriteByte(devNum, (unsigned char) ReadAddr );
    for ( i = 0; i < NumByteToRead; i++ )
    {
        pBuffer[i] = SPIFLASH_readWriteByte(devNum, 0XFF );
    }
    SPIFLASH_CSN_SET( devNum,1);
    return 0;
}


static unsigned char SPIFLASH_BUFFER[4096]= {0};
/* -------------------------------- begin  -------------------------------- */
/**
  * @Name    SPIFLASH_write
  * @brief
  * @param   devNum: [输入/出]
**			 pBuffer: [输入/出]
**			 WriteAddr: [输入/出]
**			 NumByteToWrite: [输入/出]
  * @retval
  * @author  {}
  * @Data    2023-03-02
 **/
/* -------------------------------- end -------------------------------- */

uint8_t SPIFLASH_write(unsigned char devNum,  unsigned char* pBuffer, unsigned long int WriteAddr, unsigned short int NumByteToWrite )
{
    unsigned long int	secpos;
    unsigned short int	secoff;
    unsigned short int	secremain;
    unsigned short int	i;
    unsigned char		* SPIFLASH_BUF;
    SPIFLASH_BUF	= SPIFLASH_BUFFER;
    secpos		= WriteAddr / 4096;
    secoff		= WriteAddr % 4096;
    secremain	= 4096 - secoff;
    if ( NumByteToWrite <= secremain )
        secremain = NumByteToWrite;
    while ( 1 )
    {
        SPIFLASH_read(devNum,  SPIFLASH_BUF, secpos * 4096, 4096 );
        for ( i = 0; i < secremain; i++ )
        {
            if ( SPIFLASH_BUF[secoff + i] != 0XFF )
                break;
        }
        if ( i < secremain )
        {
            SPIFLASH_eraseSector(devNum,  secpos );
            for ( i = 0; i < secremain; i++ )
            {
                SPIFLASH_BUF[i + secoff] = pBuffer[i];
            }
            SPIFLASH_writeNoCheck(devNum,  SPIFLASH_BUF, secpos * 4096, 4096 );
        } else SPIFLASH_writeNoCheck(devNum,  pBuffer, WriteAddr, secremain );
        if ( NumByteToWrite == secremain )
            break;
        else {
            secpos++;
            secoff = 0;

            pBuffer		+= secremain;
            WriteAddr	+= secremain;
            NumByteToWrite	-= secremain;
            if ( NumByteToWrite > 4096 )
                secremain = 4096;
            else
                secremain = NumByteToWrite;
        }
    }
    return 0;
}


/* -------------------------------- begin  -------------------------------- */
/**
  * @Name    SPIFLASH_eraseChip
  * @brief
  * @param   devNum: [输入/出]
  * @retval
  * @author  {}
  * @Data    2023-03-02
 **/
/* -------------------------------- end -------------------------------- */

void SPIFLASH_eraseChip(uint8_t devNum  )
{
    SPIFLASH_writeEnable(devNum );
    SPIFLASH_waitBusy(devNum);
    SPIFLASH_CSN_SET( devNum, 0);
    SPIFLASH_readWriteByte( devNum,SPIFLASH_ChipErase );
    SPIFLASH_CSN_SET( devNum, 1);
    SPIFLASH_waitBusy(devNum);
}

/* -------------------------------- begin  -------------------------------- */
/**
  * @Name    SPIFLASH_eraseSector
  * @brief
  * @param   devNum: [输入/出]
**			 Dst_Addr: [输入/出]
  * @retval
  * @author  {}
  * @Data    2023-03-02
 **/
/* -------------------------------- end -------------------------------- */

void SPIFLASH_eraseSector(uint8_t devNum, unsigned long int Dst_Addr )
{
    Dst_Addr *= 4096;
    SPIFLASH_writeEnable(devNum  );
    SPIFLASH_waitBusy(devNum  );
    SPIFLASH_CSN_SET(  devNum, 0);
    SPIFLASH_readWriteByte(devNum,  SPIFLASH_SectorErase );
    SPIFLASH_readWriteByte(devNum,  (unsigned char) ( (Dst_Addr) >> 16) );
    SPIFLASH_readWriteByte(devNum,  (unsigned char) ( (Dst_Addr) >> 8) );
    SPIFLASH_readWriteByte(devNum,  (unsigned char) Dst_Addr );
    SPIFLASH_CSN_SET( devNum, 1);
    SPIFLASH_waitBusy(devNum );
}

/* -------------------------------- begin  -------------------------------- */
/**
  * @Name    SPIFLASH_waitBusy
  * @brief
  * @param   devNum: [输入/出]
  * @retval
  * @author  {}
  * @Data    2023-03-02
 **/
/* -------------------------------- end -------------------------------- */

void SPIFLASH_waitBusy(uint8_t devNum  )
{
    while ( (SPIFLASH_readSR(devNum) & 0x01) == 0x01 )
        ;
}

/* -------------------------------- begin  -------------------------------- */
/**
  * @Name    SPIFLASH_powerDown
  * @brief
  * @param   devNum: [输入/出]
  * @retval
  * @author  {}
  * @Data    2023-03-02
 **/
/* -------------------------------- end -------------------------------- */

void SPIFLASH_powerDown( uint8_t devNum )
{
    SPIFLASH_CSN_SET( devNum, 0);
    SPIFLASH_readWriteByte(devNum, SPIFLASH_PowerDown );
    SPIFLASH_CSN_SET( devNum, 1);
}


/* -------------------------------- begin  -------------------------------- */
/**
  * @Name    SPIFLASH_wakeUp
  * @brief
  * @param   devNum: [输入/出]
  * @retval
  * @author  {}
  * @Data    2023-03-02
 **/
/* -------------------------------- end -------------------------------- */

void SPIFLASH_wakeUp( uint8_t devNum )
{
    SPIFLASH_CSN_SET( devNum, 0);
    SPIFLASH_readWriteByte(devNum, SPIFLASH_ReleasePowerDown );
    SPIFLASH_CSN_SET( devNum, 1);
}
